﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace TfsStatus.Tfs
{
	// TODO: likely concurrency issues with static VCS access
	public static class ChangeSetProvider
	{
		public static event EventHandler TfsConnected;

		private static readonly Uri _tfsUri;
		private static readonly string _vcsPath;
		
		private static VersionControlServer _vcs;
		private static VersionControlServer Vcs
		{
			get
			{
				if (_vcs == null)
					InitTfsConnection();
				return _vcs;
			}
		}

		private static TswaClientHyperlinkService _tswaLinker;
		private static TswaClientHyperlinkService TswaLinker
		{
			get
			{
				if (_tswaLinker == null)
					InitTfsConnection();
				return _tswaLinker;
			}
		}

		public static void OnTfsConnected()
		{
			EventHandler handler = TfsConnected;
			if (handler != null) handler(null, null);
		}

		static ChangeSetProvider()
		{
			_tfsUri = new Uri(ConfigurationManager.AppSettings["TfsUri"]);
			_vcsPath = ConfigurationManager.AppSettings["VcsPath"];
		}

		public static IEnumerable<Models.ChangeSet> GetChangesetsSince(DateTime since)
		{
			var tfsChangeSets = Vcs.QueryHistory(
				_vcsPath,
				VersionSpec.Latest,
				0,
				RecursionType.Full,
				null,
				new DateVersionSpec(since),
				new DateVersionSpec(DateTime.Now),
				10,
				true,
				false);

			return tfsChangeSets
				.Cast<Changeset>()
				.Select(
					changeset => new Models.ChangeSet
					{
						ChangeDateTime = changeset.CreationDate,
						Comment = changeset.Comment.Replace("***NO_CI***", "").TrimEnd('\r', '\n'),
						Id = changeset.ChangesetId,
						Url = TswaLinker.GetChangesetDetailsUrl(changeset.ChangesetId).ToString(),
						UserName = RemoveDomain(changeset.OwnerDisplayName),
						WorkItems = changeset.WorkItems
									.Select(
										wi => new Models.WorkItem
										{
											Id = wi.Id,
											Title = wi.Title,
											Url = TswaLinker.GetWorkItemEditorUrl(wi.Id).ToString()
										})
									.ToList(),
						Files = changeset.Changes
									.Select(
										change => new Models.VcsFile
										{
											ChangeType = change.ChangeType.ToString(),
											FilePath = change.Item.ServerItem.Replace(_vcsPath, String.Empty),
											Url = GetVcsFileUrl(changeset, change)
										})
									.ToList()
					});
		}

		private static string GetVcsFileUrl(Changeset changeset, Change change)
		{
			if (change.ChangeType == ChangeType.Edit)
			{
				return TswaLinker.GetDifferenceSourceControlItemsUrl(
					change.Item.ServerItem,
					"P" + changeset.ChangesetId.ToString(),
					change.Item.ServerItem,
					changeset.ChangesetId.ToString()).ToString();
			}

			return TswaLinker.GetViewSourceControlItemUrl(change.Item.ServerItem, changeset.ChangesetId).ToString();
		}

		private static void InitTfsConnection()
		{
			TfsTeamProjectCollection project = new TfsTeamProjectCollection(_tfsUri, CredentialCache.DefaultNetworkCredentials);
			project.EnsureAuthenticated();

			OnTfsConnected();

			_vcs = project.GetService<VersionControlServer>();
			_tswaLinker = project.GetService<TswaClientHyperlinkService>();
		}

		private static string RemoveDomain(string userName)
		{
			int backslashIndex = userName.IndexOf(@"\", StringComparison.OrdinalIgnoreCase);
			return userName.Substring(backslashIndex + 1,  userName.Length - backslashIndex - 1);
		}
	}
}